#include <tpunb.h>
#include <unistd.h>
#include <server.h>
#include <devnode.h>
#include <mqtt_client.h>

#define	DEFAULT_WG_ADDR		0xFFFE	//呼叫器组网默认地址					65470  -  65534
#define	DEFAULT_WG_CELLID	0x0		//呼叫器组网默认小区ID				0  	-  255
#define	DEFAULT_WG_GROUP	0x0		//呼叫器组网默认分组地址				65405  -  65469

static const char cmd_at[] = "+++\r\n";
static const char cmd_trans[] = "at+exit\r\n";
int fd_serial_tpunb;
Queue tpunbStack[QUEUE_COUNT];
pthread_mutex_t tpunbStackMutex = PTHREAD_MUTEX_INITIALIZER;
static unsigned short tpunb_module_ok = 0;

static unsigned char tpunb_handle_buf[1050] = {FRAME_HEAD, FRAME_HEAD};
static volatile unsigned short tpunb_handle_buf_idx = 0;
static unsigned short frame_pkg_len;
static char tpunb_esn[16] = {0};

static int dequeue_stop = 0;

static unsigned short addr_toset;
static unsigned char cellid_toset;
static unsigned short group_toset;

static unsigned short gw_addr = DEFAULT_WG_ADDR;
static unsigned char gw_cellid = DEFAULT_WG_CELLID;
static unsigned short gw_group = DEFAULT_WG_GROUP;

static volatile hydrology_stu_t frame_status = HYD_FRAME_HEAD;

typedef enum {
	TPUNB_STATE_NULL,				//空闲
	TPUNB_STATE_RESET_NETINFO,		//复位网络
	TPUNB_STATE_SET_NETINFO,		//设置网络
	TPUNB_STATE_GET_RELAY_REBOOT,	//获取中继,会先重启窄带模块
	TPUNB_STATE_GET_RELAY,			//获取中继
} TPUNB_STATE;

static TPUNB_STATE tpunb_state	= TPUNB_STATE_NULL;

static void stop_dequeue_tx(void)
{
	dequeue_stop = 1;
}

static void start_dequeue_tx(void)
{
	dequeue_stop = 0;
}

int is_dequeue_start(void)
{
	return dequeue_stop == 0;
}

int is_tpunb_ok(void)
{
	if(tpunb_module_ok == 0) {
		return 0;
	}

	//通信正常	
	return 1;
}

static void set_tpunb_ok(void)
{
	if(!tpunb_module_ok) {
		DEBUG("tpunb_module_ok");
		tpunb_module_ok = 1;
	}
}

int get_gw_addr(void)
{
	return gw_addr;
}

int get_gw_cellid(void)
{
	return gw_cellid;
}

int get_gw_group(void)
{
	return gw_group;
}

void gw_netInfo_settings_rsp(void)
{
	char *out;
	cJSON *root;
	char addr_str[32] = {0};

	sprintf(addr_str, "%04X", get_gw_addr());
	
	root = cJSON_Create("setNetinfo");
	cJSON_AddStringToObject(root, "gwAddr", addr_str);
	cJSON_AddStringToObject(root, "terminalgwid", get_terminal_gwsn());
	cJSON_AddNumberToObject(root, "gwCellid", get_gw_cellid());
	cJSON_AddNumberToObject(root, "gwGroup", get_gw_group());
	cJSON_AddNumberToObject(root, "ret", 0);
	out = cJSON_PrintUnformatted(root);
	cJSON_Delete(root);
	gw_publish_setting_rsp_data(out, strlen(out));
	free(out);
}

void devNode_netInfo_settings_rsp(char *devNode_sn, unsigned short addr, unsigned char cellid)
{
	char *out;
	cJSON *root, *data;
	char addr_str[32] = {0};
	char gwaddr_str[32] = {0};

	sprintf(addr_str, "%04X", addr);
	sprintf(gwaddr_str, "%04X", get_gw_addr());

	root = cJSON_Create("setdevNodeNetinfo");
	cJSON_AddStringToObject(root, "gwAddr", gwaddr_str);
	cJSON_AddNumberToObject(root, "gwCellid", get_gw_cellid());
	cJSON_AddNumberToObject(root, "ret", 0);
	cJSON_AddItemToObject(root, "data", data = cJSON_CreateObject());
	cJSON_AddStringToObject(data, "devSn", devNode_sn);
	cJSON_AddStringToObject(data, "addr", addr_str);
	cJSON_AddNumberToObject(data, "cellid", cellid);
	out = cJSON_PrintUnformatted(root);
	cJSON_Delete(root);
	gw_publish_setting_rsp_data(out, strlen(out));
	free(out);
}

void tpunb_data_timeout_callback(void)
{
	if(tpunb_state != TPUNB_STATE_NULL) {
		stop_dequeue_tx();

		switch(tpunb_state) {
			case TPUNB_STATE_RESET_NETINFO:
			case TPUNB_STATE_SET_NETINFO:
			{
				//配置网络
				if(tpunb_setNetInfo(addr_toset, cellid_toset, group_toset) == 0) {
					save_netinfo_to_file(addr_toset, cellid_toset, group_toset);
					gw_addr = addr_toset;
					gw_cellid = cellid_toset;
					gw_group = group_toset;
					DEBUG("gw_addr:%04X,gw_cellid=%d,gw_group:%04X\n", gw_addr, gw_cellid, gw_group);
					gw_netInfo_settings_rsp();
				}
				break;
			}

			case TPUNB_STATE_GET_RELAY_REBOOT:
			{
				get_tpunb_relay(1);
				break;
			}

			case TPUNB_STATE_GET_RELAY:
			{
				get_tpunb_relay(0);
				break;
			}

			default: break;
		}

		start_dequeue_tx();
		tpunb_state = TPUNB_STATE_NULL;
		tcflush(fd_serial_tpunb, TCIOFLUSH);
	}
}

//有效呼叫器地址
int valid_gw_addr(int addr)
{
	if(addr >= 65470 && addr <= 65534)	//FFBE 		FFFE
		return 1;

	return 0;
}

//有效中继地址
int valid_relay_addr(int addr)
{
	if(addr >= 60001 && addr <= 65000)	//EA61 		FDE8
		return 1;

	return 0;
}

//判断报警器地址有效
int valid_devnode_addr(int addr)
{
	if(addr >= 0 && addr <= 60000)
		return 1;

	return 0;
}

//有效小区ID
int valid_cellid(int cellid)
{
	if(cellid >= 0 && cellid <= 255)
		return 1;

	return 0;
}

//有效组播地址
int valid_group(int group)
{
	if(group == 0)
		return 1;
	
	if(group >= 65405 && group <= 65469)
		return 1;

	return 0;
}

int netInfo_settings(int addr, int cellid, int group)
{
	if(addr < 0 || cellid < 0 || group < 0) {
		tpunb_state = TPUNB_STATE_RESET_NETINFO;
		addr_toset = DEFAULT_WG_ADDR;
		cellid_toset = DEFAULT_WG_CELLID;
		group_toset = DEFAULT_WG_GROUP;
		return 0;
	} else {
		addr = (addr == 0) ? get_gw_addr() : addr;
		group = (group == 0) ? get_gw_group() : group;
		if(valid_gw_addr(addr) && valid_cellid(cellid) && valid_group(group)) {
			tpunb_state = TPUNB_STATE_SET_NETINFO;
			addr_toset = addr;
			cellid_toset = cellid;
			group_toset = group;
			return 0;
		}
	}

	return -1;
}

void get_netinfo_from_file(void)
{
	cJSON *root;
	cJSON *value;
	char gw_addr_str[16] = {0};
	
	root = parse_root_from_file(DEV_FILE);
	if(root)
	{
		value = cJSON_GetObjectItem(root, "addr");
		if(value)
		{
			if(value->type == cJSON_Number) {
				gw_addr = value->valueint;
			} else if(value->type == cJSON_String) {
				gw_addr = strtoul(value->valuestring, NULL, 16);
			}

			sprintf(gw_addr_str, "%04X", gw_addr);
			cJSON_ReplaceItemInObject(root, "addr", cJSON_CreateString(gw_addr_str));
		}
		else
		{
			gw_addr = DEFAULT_WG_ADDR;
			sprintf(gw_addr_str, "%04X", gw_addr);
			//cJSON_AddNumberToObject(root, "addr", gw_addr);
			cJSON_AddStringToObject(root, "addr", gw_addr_str);
		}

		value = cJSON_GetObjectItem(root, "cellid");
		if(value)
		{
			gw_cellid = value->valueint;
		}
		else
		{
			gw_cellid = DEFAULT_WG_CELLID;
			cJSON_AddNumberToObject(root, "cellid", gw_cellid);
		}

		value = cJSON_GetObjectItem(root, "group");
		if(value)
		{
			gw_group = value->valueint;
		}
		else
		{
			gw_group = DEFAULT_WG_GROUP;
			cJSON_AddNumberToObject(root, "group", gw_group);
		}

		save_root_to_file(root, DEV_FILE);
		free_root(root);
	}

	DEBUG("gw_addr:%04X,gw_cellid=%d,gw_group=%04X\n", gw_addr, gw_cellid, gw_group);
}

void save_netinfo_to_file(unsigned short addr, unsigned char cellid, unsigned short group)
{
	cJSON *root;
	cJSON *value;
	char addr_str[16] = {0};
	
	root = parse_root_from_file(DEV_FILE);
	if(root)
	{
		value = cJSON_GetObjectItem(root, "addr");
		if(value)
		{
			sprintf(addr_str, "%04X", addr);
			cJSON_ReplaceItemInObject(root, "addr", cJSON_CreateString(addr_str));
		}

		value = cJSON_GetObjectItem(root, "cellid");
		if(value)
		{
			cJSON_ReplaceItemInObject(root, "cellid", cJSON_CreateNumber(cellid));
		}

		value = cJSON_GetObjectItem(root, "group");
		if(value)
		{
			cJSON_ReplaceItemInObject(root, "group", cJSON_CreateNumber(group));
		}

		save_root_to_file(root, DEV_FILE);
		free_root(root);
	}
}


static int tpunb_recv_data(int fd, char *reply)
{
	int ret;
	int len = 0;
	fd_set fds;
	struct timeval timeout;

	while(1)
	{
		timeout.tv_sec = 1;
		timeout.tv_usec = 500000;
		FD_ZERO(&fds);
		FD_SET(fd, &fds);
		ret = select(fd+1, &fds, NULL, NULL, &timeout);
		if(ret == 0)
		{
			//DEBUG("tpunb_recv_data timeout break");
			break;
		}
		else if(ret == -1)
		{
			continue;
		}
		else
		{
			len += read(fd, &reply[len], 1024);
			//DEBUG("len=%d,%s", len, reply);
		}
	}

	return len;
}

static int tpunb_write_atcmd(int fd, const char *atcmd, char *reply)
{
	int ret;
    write(fd, atcmd, strlen(atcmd));
	ret = tpunb_recv_data(fd, reply);
	
	if(strstr(reply, "OK")) {
		set_tpunb_ok();
	}

	return ret;
}

char * get_tpunb_sn(void)
{
	return tpunb_esn;
}

static void *tpunbInit_thread(void *arg)
{
	int ret;
	char rx[4096];
	char at_cmd[256] = {0};
	int count;

	stop_dequeue_tx();

	for(count=0; count<3; count++) {
		memset(rx, 0, sizeof(rx));
		tpunb_write_atcmd(fd_serial_tpunb, cmd_at, rx);
		//DEBUG("recv:%s", rx);
	}

	memset(rx, 0, sizeof(rx));
	ret = tpunb_write_atcmd(fd_serial_tpunb, cmd_at, rx);			//切换AT模式
	DEBUG("recv:%s,ret=%d\n", rx,ret);

	if(gw_group == 0) {
		sprintf(at_cmd, "at+addr=%X\r\n", gw_addr);
	} else {
		sprintf(at_cmd, "at+addr=%X,%X\r\n", gw_addr, gw_group);
	}
	memset(rx, 0, sizeof(rx));
	ret = tpunb_write_atcmd(fd_serial_tpunb, at_cmd, rx);			//配置地址
	DEBUG("recv:%s,ret=%d,cmd:%s\n", rx,ret,at_cmd);
	//sleep(2);

	sprintf(at_cmd, "at+cell=%d\r\n", gw_cellid);
	memset(rx, 0, sizeof(rx));
	ret = tpunb_write_atcmd(fd_serial_tpunb, at_cmd, rx);			//配置小区ID
	DEBUG("recv:%s,ret=%d,cmd:%s\n", rx,ret,at_cmd);
	//sleep(2);

	sprintf(at_cmd, "at+trans=3,0\r\n");
	memset(rx, 0, sizeof(rx));
	ret = tpunb_write_atcmd(fd_serial_tpunb, at_cmd, rx);			//配置透传模式
	DEBUG("recv:%s,ret=%d,cmd:%s\n", rx,ret,at_cmd);
	//sleep(2);

	memset(rx, 0, sizeof(rx));
	ret = tpunb_write_atcmd(fd_serial_tpunb, cmd_trans, rx);		//退出AT模式
	DEBUG("recv:%s,ret=%d\n", rx,ret);

	start_dequeue_tx();

    tcflush(fd_serial_tpunb, TCIOFLUSH);

	return NULL;
}

void tpunbInit(void)
{
	int index;

	get_netinfo_from_file();

	for(index=0; index<QUEUE_COUNT; index++) {
		queue_init(&tpunbStack[index], QUEUE_MAX_SIZE);
	}

	//RK3566 平台
    fd_serial_tpunb = serial_open_port(SERIAL_TPUNB_RK3566);
    if (fd_serial_tpunb == -1) {
		//IMX6UL 平台
	    fd_serial_tpunb = serial_open_port(SERIAL_TPUNB_IMX6UL);
	    if (fd_serial_tpunb == -1) {
			return;
	    }
    }

    serial_set_opt(fd_serial_tpunb, 115200, 8, 'N', 1);

    tcflush(fd_serial_tpunb, TCIOFLUSH);

	create_thread(tpunbInit_thread, NULL);
}

void tpunbDeinit(void)
{
	int index;
	
	for(index=0; index<QUEUE_COUNT; index++) {
		queue_free(&tpunbStack[index]);
	}
	
    close(fd_serial_tpunb);
}

int tpunb_setNetInfo(unsigned short addr, unsigned char cellid, unsigned short group)
{
	int ret;
	char at_cmd[64] = {0};
    char rx[4096] = {0};

	if(addr == 0) {
		return -1;
	}

    memset(rx, 0, sizeof(rx));
	ret = tpunb_write_atcmd(fd_serial_tpunb, "+++\r\n", rx);	//进入AT模式
	if(ret <= 0) {
		return -1;
	}
	DEBUG("rx=%s", rx);

	if(group == 0) {
		sprintf(at_cmd, "at+addr=%X\r\n", addr);
	} else {
		sprintf(at_cmd, "at+addr=%X,%X\r\n", addr, group);
	}
	DEBUG("at_cmd=%s", at_cmd);
	ret = tpunb_write_atcmd(fd_serial_tpunb, at_cmd, rx);	//配置地址,会导致模块重启
	if(ret <= 0) {
		return -1;
	}
	DEBUG("rx=%s", rx);
	//sleep(2);

	sprintf(at_cmd, "at+cell=%d\r\n", cellid);
	DEBUG("at_cmd=%s", at_cmd);
	ret = tpunb_write_atcmd(fd_serial_tpunb, at_cmd, rx);	//配置分组,会导致模块重启
	if(ret <= 0) {
		return -1;
	}
	DEBUG("rx=%s", rx);
	//sleep(2);

	sprintf(at_cmd, "at+trans=3,0\r\n");
	ret = tpunb_write_atcmd(fd_serial_tpunb, at_cmd, rx);	//透传模式,会导致模块重启
	if(ret <= 0) {
		return -1;
	}
	DEBUG("at_cmd:%s,rx=%s", at_cmd, rx);
	//sleep(2);

	ret = tpunb_write_atcmd(fd_serial_tpunb, "at+exit\r\n", rx);	//退出AT模式
	if(ret <= 0) {
		return -1;
	}
	DEBUG("rx=%s", rx);

	//DEBUG("tpunb_resetNetInfo ok");

	return 0;
}

void set_getrelay_opr(bool reboot_tpunb)
{
	if(reboot_tpunb) {
		tpunb_state = TPUNB_STATE_GET_RELAY_REBOOT;
	} else {
		tpunb_state = TPUNB_STATE_GET_RELAY;
	}
}

int get_tpunb_relay(bool reboot_tpunb)
{
#define AT_RECV_SIZE	(1024*1024*4)

	int ret;
	char rx[1024];
	char gwaddr_str[32] = {0};

	char *out;
	cJSON *root;

	cJSON *data, *element;

	char *token;
	const char *delim = "\r\n";

	char addr_str[64] = {0};
	char rssi_str[64] = {0};
	unsigned short addr;
	DEV_NODE *devnode;

	int loc_rssi;
	int rmot_rssi;

	char *recv_buf = malloc(AT_RECV_SIZE);
	if(recv_buf == NULL) {
		goto relay_exit;
	}

    memset(rx, 0, sizeof(rx));
	ret = tpunb_write_atcmd(fd_serial_tpunb, "+++\r\n", rx);					//进入AT模式
	if(ret <= 0) {
		goto relay_exit;
	}
	//DEBUG("rx=%s", rx);

	if(reboot_tpunb) {
	    memset(rx, 0, sizeof(rx));
		ret = tpunb_write_atcmd(fd_serial_tpunb, "at+reboot\r\n", rx);			//重启模块
		if(ret <= 0) {
			goto relay_exit;
		}
		//DEBUG("rx=%s", rx);

		second_sleep(5);
	}

    tcflush(fd_serial_tpunb, TCIOFLUSH);

    //memset(rx, 0, sizeof(rx));
	//ret = tpunb_write_atcmd(fd_serial_tpunb, "at\r\n", rx);
	//if(ret <= 0) {
	//	goto relay_exit;
	//}
	//DEBUG("rx=%s", rx);

    memset(recv_buf, 0, AT_RECV_SIZE);
	ret = tpunb_write_atcmd(fd_serial_tpunb, "at+dump=nb\r\n", recv_buf);		//查询邻居信息 NB
	if(ret <= 0) {
		goto relay_exit;
	}

    memset(rx, 0, sizeof(rx));
	ret = tpunb_write_atcmd(fd_serial_tpunb, "at+exit\r\n", rx);				//退出AT模式
	if(ret <= 0) {
		goto relay_exit;
	}
	//DEBUG("rx=%s", rx);

	sprintf(gwaddr_str, "%04X", get_gw_addr());
	root = cJSON_Create("tpunb_relay");
	cJSON_AddStringToObject(root, "addr", gwaddr_str);
	cJSON_AddNumberToObject(root, "cellid", get_gw_cellid());

	cJSON_AddItemToObject(root, "data", data = cJSON_CreateArray());

	token = strtok(recv_buf, delim);
	while(token) {
		if(strncmp(token, "addr[0x", 7) == 0) {
			memset(addr_str, 0, sizeof(addr_str));
			memcpy(addr_str, &token[7], 4);
			addr = strtoul(addr_str, NULL, 16);

			token = strtok(NULL, delim);
			memset(rssi_str, 0, sizeof(rssi_str));
			memcpy(rssi_str, strchr(token, '[') + 1, strchr(token, ']') - strchr(token, '[') - 1);
			sscanf(rssi_str, "%d:%d", &loc_rssi, &rmot_rssi);

			DEBUG("addr:%s loc_rssi:%d rmot_rssi:%d", addr_str, loc_rssi, rmot_rssi);

			devnode = get_dev_node_by_addr(addr);
			if(valid_relay_addr(addr) || valid_devnode_addr(addr)) {
				element = cJSON_CreateObject();
				cJSON_AddNumberToObject(element, "addrInt", addr);
				cJSON_AddStringToObject(element, "addr", addr_str);
				cJSON_AddBoolToObject(element, "is_relaydev", valid_relay_addr(addr));
				if(devnode)
					cJSON_AddStringToObject(element, "devSn", devnode->dev_sn);
				cJSON_AddNumberToObject(element, "loc_rssi", loc_rssi); 		//网关对中继信号, loc_rssi 表示本节点收到 addr 的 rssi
				cJSON_AddNumberToObject(element, "rmot_rssi", rmot_rssi);		//中继对网关信号, rmote_rssi 表示 addr 收到本节点的 rssi
				cJSON_AddItemToArray(data, element);
			}
		}

		token = strtok(NULL, delim);
	}

	//cJSON_AddStringToObject(root, "relay_info", recv_buf);
	out = cJSON_PrintUnformatted(root);
	cJSON_Delete(root);
	gw_publish_notify_req_data(out, strlen(out));
	free(out);

relay_exit:

	if(recv_buf)
		free(recv_buf);

	return 0;
}

void enqueue_node(int queue_index, QueueNode *new_node)
{
	if(queue_index < QUEUE_COUNT) {
		enqueue(&tpunbStack[queue_index], new_node);
	}
}

void *tpunbTxLoop(void *arg)
{
	QueueNode *queue_node;
	unsigned char buf[2048];
	char txBufStr[2048];
	int i = 0;

	int queue_index;

	pthread_mutex_lock(&tpunbStackMutex);
	for(queue_index=0; queue_index < QUEUE_COUNT; queue_index++) 
	{
		queue_node = dequeue(&tpunbStack[queue_index]);
		if(queue_node != NULL) 
		{
			break;
		}
	}
	pthread_mutex_unlock(&tpunbStackMutex);

	if (queue_node != NULL) 
	{
		hydrology_head_t *pkgHead;
		unsigned short txLen;

		pkgHead = (hydrology_head_t *)queue_node->buf;
		txLen = (((unsigned short)(pkgHead->pkg_len[0] & 0x7F)) << 8) | pkgHead->pkg_len[1];
		txLen += FRAME_PADDING_LEN;
	
		buf[i++] = (queue_node->addr >> 8) & 0xFF;
		buf[i++] = (queue_node->addr) & 0xFF;

		if(txLen < 100) 
		{
			buf[i++] = 0x00;	//传输小数据流
		} 
		else 
		{
			buf[i++] = 0x01;	//传输大数据流
		}
		
		memcpy(&buf[i], queue_node->buf, txLen);
		txLen += i;
		
		write(fd_serial_tpunb, buf, txLen);
		if(txLen < 100)
		{
			hex2string(txBufStr, buf, txLen);
			txBufStr[txLen*2] = 0;

			if(queue_node->addr)
			{
				DEBUG("txLen=%d to_addr:%04X %s", txLen - i, queue_node->addr, &txBufStr[6]);
			}
			else
			{
				DEBUG("txLen=%d %s", txLen - i, &txBufStr[6]);
			}
		}
		else
		{
			hex2string(txBufStr, buf, 100);
			txBufStr[100*2] = 0;
			DEBUG("txLen=%d %s", txLen - i, txBufStr);
		}

		if(queue_node->usec_delay > 0) usleep(queue_node->usec_delay);
		free(queue_node->buf);
		free(queue_node);
	} 
	else
	{
		usleep(100000);	//队列为空
	}

    return NULL;
}

void *tpunbRxLoop(void *arg)
{
    int len, tail;
	int total_len;
	static int offset = 0;
    static unsigned char rxBuf[2048];
	static char rxBufStr[4096];

    if ((len = read(fd_serial_tpunb, &rxBuf[offset], 1024)) < 0) {
        DEBUG("tpunb read error");
        return NULL;
    }

	offset += len;
	total_len = offset;
	hex2string(rxBufStr, rxBuf, total_len);
	rxBufStr[total_len*2] = 0;
	DEBUG("tpunb read:len=%d,total=%d,%s", len, total_len, rxBufStr);

    tail = 0;
	int is_pkg_up = 0;
	frame_status = HYD_FRAME_HEAD;
	tpunb_handle_buf_idx = 0;
    while (tail < total_len) {
        unsigned char rxdata = rxBuf[tail++];
        switch (frame_status) {
            case HYD_FRAME_HEAD:
                if (rxdata == FRAME_HEAD) {
                    tpunb_handle_buf[tpunb_handle_buf_idx++] = rxdata;
                    if (tpunb_handle_buf_idx == FRAME_OFFSET_CENTER_ADDR)
                        frame_status = HYD_FRAME_CENTER_ADDR;
                } else {
                    tpunb_handle_buf_idx = 0;
					--total_len;if(total_len<0)total_len=0;
					--offset;if(offset<0)offset=0;
					--tail;if(tail<0)tail=0;
                }
                break;

            case HYD_FRAME_CENTER_ADDR:
                tpunb_handle_buf[tpunb_handle_buf_idx++] = rxdata;
                frame_status = HYD_FRAME_REMOTER_ADDR;
                break;

            case HYD_FRAME_REMOTER_ADDR:
                tpunb_handle_buf[tpunb_handle_buf_idx++] = rxdata;
                if (tpunb_handle_buf_idx == FRAME_OFFSET_PASSWD)
                    frame_status = HYD_FRAME_PASSWORD;
                break;

            case HYD_FRAME_PASSWORD:
                tpunb_handle_buf[tpunb_handle_buf_idx++] = rxdata;
                if (tpunb_handle_buf_idx == FRAME_OFFSET_CMDTYPE)
                    frame_status = HYD_FRAME_CMDTYPE;
                break;

            case HYD_FRAME_CMDTYPE:
                tpunb_handle_buf[tpunb_handle_buf_idx++] = rxdata;
                frame_status = HYD_FRAME_PKGLEN;
                break;

            case HYD_FRAME_PKGLEN:
                tpunb_handle_buf[tpunb_handle_buf_idx++] = rxdata;
                if (tpunb_handle_buf_idx == FRAME_OFFSET_PKGBEGIN)
                    frame_status = HYD_FRAME_BEGIN;
                break;

            case HYD_FRAME_BEGIN:
                tpunb_handle_buf[tpunb_handle_buf_idx++] = rxdata;
                if ((tpunb_handle_buf[FRAME_OFFSET_PKGBEGIN - 2] & 0xF0) == 0) {
                    //DEBUG("up...");//该数据包是上行，由报警器发出
                    is_pkg_up=1;
                } else {
                    //DEBUG("down...");	//下行有呼叫器发出
                    is_pkg_up=0;
                }
                if (rxdata == FRAME_STX) {
                    frame_pkg_len = ((unsigned short)(tpunb_handle_buf[FRAME_OFFSET_PKGBEGIN - 2] & 0x0F) << 8) | 
                                        tpunb_handle_buf[FRAME_OFFSET_PKGBEGIN - 1];
                    //DEBUG("normal");
                } else if (rxdata == FRAME_SYN) {
                    frame_pkg_len = ((unsigned short)(tpunb_handle_buf[FRAME_OFFSET_PKGBEGIN - 2]) << 8) | 
                                        tpunb_handle_buf[FRAME_OFFSET_PKGBEGIN - 1];
                    DEBUG("sub");
                }
                //DEBUG("frame_pkg_len=%d\n", frame_pkg_len);

				//38 + 17 = 55	> 33
				if(frame_pkg_len + FRAME_PADDING_LEN > total_len) {
					return NULL;
				}

				offset = 0;

				if(frame_pkg_len >= 1000) {
					//非法数据
					return NULL;
				}
				
                if (frame_pkg_len)
                    frame_status = HYD_FRAME_DATA;
                else
                    frame_status = HYD_FRAME_END;
                break;

            case HYD_FRAME_DATA:
                tpunb_handle_buf[tpunb_handle_buf_idx++] = rxdata;
                if (!(--frame_pkg_len))
                    frame_status = HYD_FRAME_END;
                break;

            case HYD_FRAME_END:
                tpunb_handle_buf[tpunb_handle_buf_idx++] = rxdata;
                frame_status = HYD_FRAME_CRC1;
                break;

            case HYD_FRAME_CRC1:
                tpunb_handle_buf[tpunb_handle_buf_idx++] = rxdata;
                frame_status = HYD_FRAME_CRC2;
                break;

            case HYD_FRAME_CRC2:
                {
                    unsigned short crc16;
					unsigned char *buf;
					int size;
					bool crcok = false;

                    tpunb_handle_buf[tpunb_handle_buf_idx++] = rxdata;
					buf = tpunb_handle_buf;
					size = tpunb_handle_buf_idx;
                    crc16 = do_crc16(buf, size - 2);

					//ABCD == ABCD	|| CDAB == ABCD
					if(((crc16 >> 8) == buf[size - 2]) && ((crc16 & 0xFF) == buf[size - 1])) {
						crcok = true;
					} else if(((crc16 & 0xFF) == buf[size - 2]) && ((crc16 >> 8) == buf[size - 1])) {
						crcok = true;
					}

                    if (crcok) {
                        if(is_pkg_up) {
							//只处理上行数据，即报警器发出的数据
							hydrology_analysis(buf, DATA_TYPE_TPUNB);
						}
                    } else {
						DEBUG("crc error --%X\n", crc16);
					}
                }
                frame_status = HYD_FRAME_HEAD;
                tpunb_handle_buf_idx = 0;
				//total_len -= tail; tail  = 0;
                break;
        }
    }

    return NULL;
}
